package cn.historia.trigger.job;

import cn.bugstack.middleware.db.router.strategy.IDBRouterStrategy;
import cn.historia.domain.task.model.entity.TaskEntity;
import cn.historia.domain.task.service.ITaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @package: cn.historia.trigger.job
 * @className: SendMessageTaskJob
 * @author: 云溪
 * @description: 定时从task表里找失败的记录发送MQ消息
 * @date: 2025/9/30 16:25
 * @version: 1.0
 */
@Slf4j
@Component()
public class SendMessageTaskJob {

    @Resource
    private ITaskService taskService;
    @Resource
    private ThreadPoolExecutor executor;
    @Resource
    private IDBRouterStrategy dbRouter;

    @Scheduled(cron = "*/5 * * * * ?")
    public void exec(){

        try {
            // 获取分库数量
            int dbCount = dbRouter.dbCount();

            // 因为task表是分库不分表的，每个库只有一张表
            // 逐个库扫描
            for(int i = 1; i <= dbCount; i++) {
                int dbIndex = i;
                // 异步开启线程去查询
                executor.execute(() -> {
                            try {
                                dbRouter.setDBKey(dbIndex);
                                dbRouter.setTBKey(0);
                                List<TaskEntity> taskEntities = taskService.queryNoSendMessageTaskList();
                                for (TaskEntity taskEntity : taskEntities) {
                                    // 异步发送MQ消息
                                    // 开启线程发送，提高发送效率。配置的线程池策略为 CallerRunsPolicy，在 ThreadPoolConfig 配置中有4个策略，面试中容易对比提问。可以检索下相关资料。
                                    // CallerRunsPolicy: 当任务队列满载时，提交任务的线程会直接运行该任务，从而达到缓冲作用。
                                    executor.execute(() -> {
                                        try {
                                            taskService.sendMessage(taskEntity);
                                            taskService.updateTaskSendMessageCompleted(taskEntity.getUserId(), taskEntity.getMessageId());
                                        } catch (Exception e) {
                                            log.error("定时任务，发送MQ消息失败 userId: {} topic: {}", taskEntity.getUserId(), taskEntity.getTopic());
                                            taskService.updateTaskSendMessageFail(taskEntity.getUserId(), taskEntity.getMessageId());
                                        }
                                    });
                                }
                            } finally {
                                dbRouter.clear();
                            }
                        }
                );
            }
        } catch (Exception e) {
            log.error("定时任务，扫描MQ任务表发送消息失败。", e);
        } finally {
            dbRouter.clear();
        }


    }

}
